/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sirtet.netplay.server;

import java.util.HashMap;
import java.util.Map;
import sirtet.netplay.Communicator;
import sirtet.netplay.NetworkPlayer;
import sirtet.netplay.event.CommunicationDataEvent;
import sirtet.netplay.event.CommunicationEvent;
import sirtet.netplay.event.CommunicationListener;

/**
 * A server bouncing all the input back, except for the case when the two
 * consecutive commands arrive too closely (less than a given interval).
 * This server is for simple purpose (like debugging, or local game) only.
 * @author guangwei.zhu
 */
public class BounceServer extends ServerObject {

    private final Object mapLock = new Object();
    private Map threads = new HashMap();
    private int interval;

    /**
     * Create a bouncing server without interval limit
     */
    public BounceServer() {
        this(0);
    }

    /**
     * Create a bouncing server with constraint about minimum interval
     * @param interval
     */
    public BounceServer(int interval) {
        if (interval < 0) {
            throw new IllegalArgumentException();
        }
        this.interval = interval;
    }

    @SuppressWarnings({"unchecked"})
    protected boolean admitsBounce(Representative source, String data) {

        if (!data.contains(":")) {
            return false;       // This is not an action
        }

        if (this.interval == 0) {   // Not limited
            return true;
        }

        long lastTime, passedTime;
        synchronized (mapLock) {

            if (threads.containsKey(source)) {
                lastTime = (Long) threads.get(source);
            } else {
                lastTime = -1;
            }
        }

        passedTime = System.currentTimeMillis() - lastTime;
        if (passedTime < interval) {
            return false;   // Reject too frequent actions
        }

        threads.put(source, System.currentTimeMillis());

        return true;
    }

    protected class Representative implements CommunicationListener {

        protected Communicator communicator;

        public Representative(NetworkPlayer player) {
            this.communicator = player.getCommunicator();
            communicator.addCommunicationListener(this);
        }

        public void communicationDataReceived(CommunicationDataEvent evt) {
            if (admitsBounce(this, evt.data)) {
                communicator.post(evt.data);
            }
        }

        public void communicationDisconnected(CommunicationEvent evt) {
        }
    }

    @Override
    protected void playerArrived(NetworkPlayer player) {
        new Representative(player);
    }
}
